Namespace ShapeLibrary.Design
    '''
    ''' This is a designer for the shape container class.  There are two
    ''' designers for this class:  a root designer and a normal designer.
    ''' This is the normal designer and it is used when a shape container
    ''' is placed on another component.  This designer performs a simple
    ''' bit of wiring magic -- if it is placed on a Windows Forms object,
    ''' it will automatically attach the shape it's designing to the 
    ''' paint event of the control.
    '''
    Friend Class ShapeContainerDesigner
        Inherits ComponentDesigner
        Private m_paintingControl As Control
        Private m_offerControlProp As Boolean

        '''
        ''' This is a property that we MAY add onto the shape container.
        ''' We will add this property if the shape container's root designer
        ''' is based on windows forms.
        '''
        ' Design-time properties are stored in resources.  Unforutnately this means
        ' that all design-time properties have to be serializable.  We can't save this
        ' property then because we don't want to actually serialize a control, but a
        ' reference to the control.  We handle this in our custom serializer.
        <Description("The control this shape should draw on."), _
        DesignOnly(True), _
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Private Property Control() As Control
            Get
                Return m_paintingControl
            End Get
            Set(ByVal Value As Control)
                If Not (m_paintingControl Is Nothing) Then
                    RemoveHandler m_paintingControl.Paint, New PaintEventHandler(AddressOf OnControlPaint)
                    m_paintingControl.Invalidate()
                End If

                m_paintingControl = Value

                If Not (m_paintingControl Is Nothing) Then
                    AddHandler m_paintingControl.Paint, New PaintEventHandler(AddressOf OnControlPaint)
                    m_paintingControl.Invalidate()
                End If
            End Set
        End Property

        '''
        ''' This helper property returns an instance of the ShapeContainer
        ''' object we're designing.
        '''
        Protected Overridable ReadOnly Property ShapeContainer() As ShapeContainer
            Get
                Return CType(Component, ShapeContainer)
            End Get
        End Property

        '''
        ''' We override dispose so we can disconnect our paint handler
        '''
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

            If disposing Then
                Dim cs As IComponentChangeService = CType(GetService(GetType(IComponentChangeService)), IComponentChangeService)
                If Not (cs Is Nothing) Then
                    RemoveHandler cs.ComponentRemoved, New ComponentEventHandler(AddressOf OnComponentRemoved)
                End If

                Control = Nothing
            End If
            MyBase.Dispose(disposing)
        End Sub

        '''
        ''' We override Initialize so we can connect our paint handler to
        ''' the designer's root component.
        '''
        Public Overrides Sub Initialize(ByVal component As IComponent)
            MyBase.Initialize(component)

            ' Get the root component for the design surface and
            ' see if it is a Windows Forms based thing.  If it is,
            ' connect the paint event.
            '
            Dim host As IDesignerHost = CType(GetService(GetType(IDesignerHost)), IDesignerHost)
            If Not (host Is Nothing) Then
                If TypeOf host.RootComponent Is Control Then
                    Dim control As Control = CType(host.RootComponent, Control)
                    m_offerControlProp = True
                    Me.Control = control
                End If
            End If

            Dim cs As IComponentChangeService = CType(GetService(GetType(IComponentChangeService)), IComponentChangeService)
            If Not (cs Is Nothing) Then
                AddHandler cs.ComponentRemoved, New ComponentEventHandler(AddressOf OnComponentRemoved)
            End If
        End Sub

        '''
        ''' Because we are connecting ourself to another control on the design surface, we
        ''' must listen to remove events.  If the control we're painting to is being removed,
        ''' we need to detatch the paint event we added.
        '''
        Private Sub OnComponentRemoved(ByVal sender As Object, ByVal ce As ComponentEventArgs)
            If ce.Component Is Control Then
                Control = Nothing
            End If
        End Sub

        '''
        ''' We override PreFilterProperties so we can offer our "Control" property in windows
        ''' forms based designers.
        '''
        Protected Overrides Sub PreFilterProperties(ByVal properties As IDictionary)
            MyBase.PreFilterProperties(properties)
            If m_offerControlProp Then
                properties("Control") = TypeDescriptor.CreateProperty(Me.GetType(), "Control", GetType(Control))
            End If
        End Sub

        '''
        ''' This is our paint handler for the root control.  We just delegate to
        ''' the shape container to do all the painting.
        '''
        Private Sub OnControlPaint(ByVal sender As Object, ByVal e As PaintEventArgs)
            ShapeContainer.Draw(e.Graphics)
        End Sub
    End Class
End Namespace
